/*
 * UserNet  --  TCP/IP implementation in userspace
 * Copyright (C) 2010  Robert Millan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <errno.h>
#include <error.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "unet/dev.h"
#include "unet/rpc.h"
#include "unet/misc.h"

static inline int
is_ip_in_this_net (in_addr_t ip, in_addr_t net, in_addr_t mask)
{
  return ((ip & mask) == net);
}

// FIXME: this is only here to make build happy
void
unet_ip_incoming_packet ()
{
}

static void
ifconfig_list (int id)
{
  struct unet_device device;

  if (unet_rpc_get_device_info (id, &device) == -1)
    error (1, errno, "unet_rpc_get_device_info");

  printf ("unet%u\n"
	  "          Driver: %s\n"
	  "          Datalink: %s\n"
	  "          MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n"
	  "          IP address: %s\n"
	  "\n",
	  id,
	  device.driver.name,
	  device.driver.datalink.name,
	  device.mac_addr[0], device.mac_addr[1], device.mac_addr[2],
	  device.mac_addr[3], device.mac_addr[4], device.mac_addr[5],
	  inet_ntoa (device.ip_addr));
}

int
main (int argc, char *argv[])
{
  const char *devname = argv[1];
  const int count = unet_rpc_count_devices ();
  if (count == -1)
    error (1, errno, "unet_rpc_count_devices");

  if (argc == 1)
    {
      int i;

      for (i = 0; i < count; i++)
	ifconfig_list (i);

      return 0;
    }

  if (strncmp (devname, "unet", 4))
    error (1, ENODEV, "%s", devname);

  int id = atoi (devname + 4);
  if (id >= count)
    error (1, ENODEV, "%s", devname);

  if (argc > 2)
    {
      struct unet_device device;

      if (unet_rpc_get_device_info (id, &device) == -1)
	error (1, errno, "unet_rpc_get_device_info");

      inet_aton (argv[2], &device.ip_addr);
      
      int ret = unet_rpc_set_device_info (&device);
      if (ret == -1)
	error (1, errno, "unet_rpc_set_device_info");

      struct unet_route route =
	{
	  .Gateway = { 0 },
	  .interface = &device,
	  .id_interface = device.id,
	};

      if (is_ip_in_this_net (device.ip_addr.s_addr, inet_addr ("0.0.0.0"), inet_addr ("128.0.0.0")))
	/* class A */
	route.Genmask.s_addr = inet_addr ("255.0.0.0");
      else if (is_ip_in_this_net (device.ip_addr.s_addr, inet_addr ("128.0.0.0"), inet_addr ("192.0.0.0")))
	/* class B */
	route.Genmask.s_addr = inet_addr ("255.255.0.0");
      else if (is_ip_in_this_net (device.ip_addr.s_addr, inet_addr ("192.0.0.0"), inet_addr ("224.0.0.0")))
	/* class C */
	route.Genmask.s_addr = inet_addr ("255.255.255.0");
      else
	/* other class, don't bother about default route */
	goto skip_route;

      /* Network */
      route.Destination.s_addr = device.ip_addr.s_addr & route.Genmask.s_addr;

      if (unet_rpc_route_add (&route) == -1)
	error (0, errno, "Unable to add default route");
    }
  else
    ifconfig_list (id);

 skip_route:

  return 0;
}
